<?php

	/**
	 * @package		CoreProject
	 * @subpackage	Mime
	 *
	 * cpr_Mime_Email
	 * cpr_Mime_Emails
	 *
	 */

	class cpr_Mime_Email
	{
		/**
		 * @var	string
		 */
		private $_displayName = '';

		/**
		 * @var	string
		 */
		private $_email = '';

		/**
		 * @var	string
		 */
		private $_remarks = '';

		/**
		 * @var	cpr_Mime_GlobalCharset
		 */
		private $_global_charset;

		/**
		 * @param	cpr_Mime_GlobalCharset	&$_gc
		 * @param	string					$_email = ''
		 * @param	string					$_displayName = ''
		 * @param	string					$_remarks = ''
		 * @return	cpr_Mime_Email
		 */
		public function cpr_Mime_Email(&$_gc, $_email = '', $_displayName = '', $_remarks = '')
		{
			$this->_global_charset =& $_gc;

			$this->_email = $_email;
			$this->_displayName = $_displayName;
			$this->_remarks = $_remarks;
		}

		/**
		 * @return	string
		 */
		public function Email()
		{
			return $this->_email;
		}

		/**
		 * @return	string
		 */
		public function DisplayName()
		{
			return $this->_displayName;
		}

		/**
		 * @return	string
		 */
		public function Remarks()
		{
			return $this->_remarks;
		}

		/**
		 * @return	string
		 */
		public function GetAccountName()
		{
			return self::GetAccountNameFromEmail($this->_email);
		}

		/**
		 * @return	string
		 */
		public function GetDomain()
		{
			return self::GetDomainFromEmail($this->_email);
		}

		/**
		 * @param	string	$_email
		 * @return	string
		 */
		public static function GetAccountNameFromEmail($_email)
		{
			if ($_email)
			{
				$_dPos = strpos($_email, '@');
				return (false === $_dPos) ? $_email : substr($_email, 0, $_dPos);
			}

			return '';
		}

		/**
		 * @param	string	$_email
		 * @return	string
		 */
		public static function GetDomainFromEmail($_email)
		{
			if ($_email)
			{
				$_dPos = strpos($_email, '@');
				if (false !== $_dPos)
				{
					return substr($_email, $_dPos + 1);
				}
			}
			return '';
		}

		/**
		 * @param	string	$addressString
		 * @return	bool
		 */
		function Parse($addressString)
		{
			if (!$addressString)
			{
				return false;
			}

			$addressString = trim($addressString);

			$name = '';
			$email = '';
			$comment = '';

			$inName = false;
			$inAddress = false;
			$inComment = false;

			$startIndex = 0;
			$endIndex = 0;
			$currentIndex = 0;

			while ($currentIndex < strlen($addressString))
			{
				switch ($addressString{$currentIndex})
				{
					case '"':
						if ((!$inName) && (!$inAddress) && (!$inComment))
						{
							$inName = true;
							$startIndex = $currentIndex;
						}
						elseif ((!$inAddress) && (!$inComment))
						{
							$endIndex = $currentIndex;
							$name = substr($addressString, $startIndex + 1, $endIndex - $startIndex - 1);
							$addressString = substr_replace($addressString, '', $startIndex, $endIndex - $startIndex + 1);
							$endIndex = 0;
							$currentIndex = 0;
							$startIndex = 0;
							$inName = false;
						}
						break;
					case '<':
						if ((!$inName) && (!$inAddress) && (!$inComment))
						{
							if ($currentIndex > 0 && strlen($name) == 0)
							{
								$name = substr($addressString, 0, $currentIndex - 1);
							}

							$inAddress = true;
							$startIndex = $currentIndex;
						}
						break;
					case '>':
						if ($inAddress)
						{
							$endIndex = $currentIndex;
							$email = substr($addressString, $startIndex + 1, $endIndex - $startIndex - 1);
							$addressString = substr_replace($addressString, '', $startIndex, $endIndex - $startIndex + 1);
							$endIndex = 0;
							$currentIndex = 0;
							$startIndex = 0;
							$inAddress = false;
						}
						break;
					case '(':
						if ((!$inName) && (!$inAddress) && (!$inComment))
						{
							$inComment = true;
							$startIndex = $currentIndex;
						}
						break;
					case ')':
						if ($inComment)
						{
							$endIndex = $currentIndex;
							$comment = substr($addressString, $startIndex + 1, $endIndex - $startIndex - 1);
							$addressString = substr_replace($addressString, '', $startIndex, $endIndex - $startIndex + 1);
							$endIndex = 0;
							$currentIndex = 0;
							$startIndex = 0;
							$inComment = false;
						}
						break;
					case '\\':
						$currentIndex++;
						break;
				}

				$currentIndex++;
			}

			if (strlen($email) == 0)
			{
				$regs = array('');
				if (preg_match('/[^@\s]+@\S+/i', $addressString, $regs))
				{
					$email = $regs[0];
				}
				else
				{
					$name = $addressString;
				}
			}

			if ((strlen($email) > 0) && (strlen($name) == 0) && (strlen($comment) == 0))
			{
				$name = str_replace($email, '', $addressString);
			}

			$this->_email = trim(trim($email), '<>');
			$this->_displayName = trim(trim($name),'"');
			$this->_remarks = trim(trim($comment),'()');

			return true;
		}

		/**
		 * @return string
		 */
		function ToEncodeString()
		{
			$result = '';

			if ($this->_email != '')
			{
				$NewDisplayName = (substr($this->_displayName, 0, 2) == '=?')  ? $this->_displayName :
					ConvertUtils::EncodeHeaderString($this->DisplayName, $this->_global_charset->GetMailCharset(), $this->_global_charset->GetOutCharset(), true);
				$NewRemarks = (substr($this->_remarks, 0, 2) == '=?')  ? $this->_remarks :
					ConvertUtils::EncodeHeaderString($this->Remarks, $this->_global_charset->GetMailCharset(), $this->_global_charset->GetOutCharset(), true);

				if ($this->_displayName != '' && $this->_remarks != '')
				{
					$result = '"'.$NewDisplayName.'" ';
					if (strlen($NewDisplayName.$this->_email) > CPR_MIME_LINE_LENGTH_LIMIT)
					{
						$result .= CPR_CRLF.CPR_TAB;
					}
					$result .= '<'.$this->_email.'> ';
					if (strlen($NewDisplayName.$this->_email) > CPR_MIME_LINE_LENGTH_LIMIT)
					{
						if (strlen($this->_email.$NewRemarks) > CPR_MIME_LINE_LENGTH_LIMIT)
						{
							$result .= CPR_CRLF.CPR_TAB;
						}
					}
					else
					{
						if (strlen($NewDisplayName.$this->_email.$NewRemarks) > CPR_MIME_LINE_LENGTH_LIMIT)
						{
							$result .= CPR_CRLF.CPR_TAB;
						}
					}
					$result .= '('.$NewRemarks.')';
				}
				else if ($this->_displayName != '')
				{
					$result = '"'.$NewDisplayName.'" ';
					if (strlen($NewDisplayName.$this->_email) > CPR_MIME_LINE_LENGTH_LIMIT)
					{
						$result .= CPR_CRLF.CPR_TAB;
					}
					$result .= '<'.$this->_email.'>';
				}
				else if ($this->_remarks != '')
				{
					$result = '<'.$this->_email.'>';
					if (strlen($this->_email.$NewRemarks) > CPR_MIME_LINE_LENGTH_LIMIT)
					{
						$result .= CPR_CRLF.CPR_TAB;
					}
					$result .= '('.$NewRemarks.')';
				}
				else
				{
					$result = $this->_email;
				}
			}
			else
			{
				if ($this->_displayName !== '' && $this->_remarks === '')
				{
					$result = (substr($this->_displayName, 0, 2) == '=?')  ? '"'.$this->_displayName.'"' :
						'"'.ConvertUtils::EncodeHeaderString($this->DisplayName, $this->_global_charset->GetMailCharset(), $this->_global_charset->GetOutCharset(), true).'"';
				}
				else if ($this->_displayName === '' && $this->_remarks !== '')
				{
					$result = (substr($this->_remarks, 0, 2) == '=?')  ? '('.$this->_remarks.')' :
						'('.ConvertUtils::EncodeHeaderString($this->Remarks, $this->_global_charset->GetMailCharset(), $this->_global_charset->GetOutCharset(), true).')';
				}
			}

			return $result;
		}
	}

	class cpr_Mime_Emails extends cpr_Core_Collection
	{
		/**
		 * @var	cpr_Mime_GlobalCharset
		 */
		private $_global_charset;

		/**
		 * @param	cpr_Mime_GlobalCharset	&$_gc
		 * @param	string					$_emails = null
		 * @return	cpr_Mime_Headers
		 */
		function  cpr_Mime_Headers(&$_gc, $_emails = null)
		{
			$this->_global_charset =& $_gc;

			if (null !== $_emails)
			{
				$this->Parse($_emails);
			}
		}

		/**
		 * @param	string	$recipients
		 * @return	bool
		 */
		function Parse($_emails)
		{
			if (!$_emails)
			{
				return false;
			}

			$sWorkingRecipients = trim($_emails);

			$emailStartPos = 0;
			$emailEndPos = 0;

			$isInQuotes = false;
			$chQuote = '"';
			$isInAngleBrackets = false;
			$isInBrackets = false;

			$currentPos = 0;

			$sWorkingRecipientsLen = strlen($sWorkingRecipients);

			while ($currentPos < $sWorkingRecipientsLen)
			{
				switch ($sWorkingRecipients{$currentPos})
				{
					case '\'':
					case '"':
						if (!$isInQuotes)
						{
							$chQuote = $sWorkingRecipients{$currentPos};
							$isInQuotes = true;
						}
						elseif ($chQuote == $sWorkingRecipients{$currentPos})
						{
							$isInQuotes = false;
						}
						break;

					case '<':
						if (!$isInAngleBrackets)
						{
							$isInAngleBrackets = true;
						}
						break;

					case '>':
						if ($isInAngleBrackets)
						{
							$isInAngleBrackets = false;
						}
						break;

					case '(':
						if (!$isInBrackets)
						{
							$isInBrackets = true;
						}
						break;

					case ')':
						if ($isInBrackets)
						{
							$isInBrackets = false;
						}
						break;

					case ',':
					case ';':
						if (!$isInAngleBrackets && !$isInBrackets && !$isInQuotes)
						{
							$emailEndPos = $currentPos;
							$addr = new cpr_Mime_Email($this->_global_charset);
							$addr->Parse(substr($sWorkingRecipients, $emailStartPos, $emailEndPos - $emailStartPos));
							$this->Add($addr);
							$emailStartPos = $currentPos + 1;
						}
						break;
				}
				$currentPos++;
			}

			if ($emailStartPos < $currentPos)
			{
				$addr = new cpr_Mime_Email($this->_global_charset);
				$addr->Parse(substr($sWorkingRecipients, $emailStartPos, $currentPos - $emailStartPos));
				$this->Add($addr);
			}

			return true;
		}

		/**
		 * @return	string
		 */
		public function ToEncodeString()
		{
			$result = '';
			if ($this->Count() > 0)
			{
				$emails =& $this->Instance();
				foreach ($emails as $email)
				{
					$result .= ($result !== '') ? CPR_TAB : '';
					$result .= $email->ToEncodeString() . ','.CPR_CRLF;
				}

				$result = substr($result, 0, strlen($result) - 1 - strlen(CPR_CRLF));
			}

			return $result;
		}
	}
